feat(mcp): add corpus-backed GitHub search and source artifacts - #249
Conversation
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ff6e440624
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if text := strings.TrimSpace(opts.Query); text != "" { | ||
| queryParts = append(queryParts, text) |
There was a problem hiding this comment.
Reject queries that escape the requested repository
When opts.Query contains a scope-changing expression such as OR repo:other/project, appending it verbatim after the fixed repo: qualifier allows GitHub to return results outside owner/repo. The application then marks those results failed while the immutable artifact records them as ordinary items, and they can consume the bounded page and hide valid in-scope matches. Reject or structurally constrain repository-changing qualifiers and boolean expressions before issuing the request.
AGENTS.md reference: AGENTS.md:L5-L6
Useful? React with 👍 / 👎.
| resolution, _, err := resolver.ResolveRepositoryRef(ctx, ref.Owner, ref.Repo, requestedRef) | ||
| if err != nil { | ||
| return fmt.Errorf("resolve contribution guidance ref %q: %w", requestedRef, err) |
There was a problem hiding this comment.
Treat empty repositories as having no guidance files
When repository-context synchronization targets a newly created or otherwise empty GitHub repository, resolving its default branch or HEAD through the commits endpoint returns GitHub's empty-repository error rather than a commit. This now aborts the entire context-sync task after metadata has already been written, whereas probing the fixed guidance paths previously treated their 404 responses as an empty, complete guidance set. Handle the empty-repository response by atomically storing an empty guidance snapshot instead of failing the repository.
Useful? React with 👍 / 👎.
| if len(file.Content) > opts.PerFileBytes { | ||
| item.Status, item.Bytes, item.Message = "too_large", len(file.Content), fmt.Sprintf("file exceeds %d-byte per-file limit", opts.PerFileBytes) |
There was a problem hiding this comment.
Classify files above GitHub's inline limit as too large
For files larger than GitHub's Contents API inline-content threshold (about 1 MiB), the response reports no decodable inline content, so GetRepositoryFileAtResolvedRef fails before this length check is reached. Such files are therefore emitted as generic failed items even when they plainly exceed the configured per-file limit, defeating the contract's distinct too_large outcome and recovery semantics. Preserve the provider-reported size/type and return too_large before attempting to decode inline content.
Useful? React with 👍 / 👎.
| contentDigest := sha256.Sum256([]byte(content)) | ||
| item.Status, item.File, item.StartLine, item.EndLine, item.Bytes, item.ContentSHA = "complete", file, startLine, endLine, len(content), hex.EncodeToString(contentDigest[:]) | ||
| item.File.Content = content |
There was a problem hiding this comment.
Reject or encode non-UTF-8 source bytes
When a requested file or selected line range contains invalid UTF-8 bytes, this code hashes the original bytes and marks the item complete, but the later encoding/json serialization of the source artifact replaces those bytes with Unicode replacement characters. The persisted content therefore no longer matches content_sha256, silently corrupting the supposedly exact source bundle. Validate UTF-8 and return a distinct failed outcome, or encode arbitrary file bytes reversibly before hashing and persistence.
Useful? React with 👍 / 👎.
Description
Add provenance-preserving live GitHub thread search and bounded source-file acquisition backed by immutable local corpus artifacts. This addresses two related workflow gaps: live search results previously had no durable, exact handoff, and source provenance could confuse a GitHub blob SHA with the resolved commit SHA.
The adapter now resolves named refs to one authoritative commit, reads source files at that commit, and keeps blob identity separate.
github.search_threadspersists returned thread observations without claiming repository-wide coverage and stores an immutablegithub-thread-search.v1artifact.github.read_source_filesstores bounded ordered files and per-item outcomes in asource-bundle.v1artifact. Both artifacts are exposed through exact, digest-bound localresources/readroutes; resource reads do not contact GitHub.The additive
corpus.search_code_batchoperation runs up to 20 code queries against one offline corpus revision, preserving each query’s existing coverage and truncation semantics. Live GitHub code search remains intentionally out of scope.Review order:
internal/githubprovenance and bounded adapter behaviorinternal/apppersistence/artifact behavior and offline code batchinginternal/mcpcontract/internal/mcpservertool, schema, and resource wiringTesting
make verify— passed (uncached short tests, golangci-lint, module tidiness, generated-output checks, and AGENTS validation).go test ./...— passed.make test-race— passed for app, corpus, and workspace packages.Compatibility and scope
corpus.search_coderemains supported.